<script setup lang="ts">
import {
  NButton,
  NDataTable,
  NCard,
  NForm,
  NFormItem,
  NInput,
  NPopconfirm,
  useMessage,
  useModal,
  NTag,
  NSelect,
  NTreeSelect,
  NNumberAnimation,
  type DataTableColumns,
  type FormRules,
  type FormInst
} from 'naive-ui'
import { reactive, ref, h, computed } from 'vue'

import * as roleApi from '@/api/role'
import { ScrollContainer } from '@/components'
import { useInjection } from '@/composables'
import { mediaQueryInjectionKey } from '@/injection'

import type { Permission } from '@/api/role'

const { isMaxMd, isMaxLg } = useInjection(mediaQueryInjectionKey)

const message = useMessage()
const modal = useModal()

// 表格数据和分页
const dataList = ref<Permission[]>([])
const isRequestLoading = ref(false)
const checkedRowKeys = ref<Array<number>>([])

// 操作列折叠状态
const isActionsExpanded = ref(false)

// 搜索表单
interface SearchForm {
  keyword: string | null | undefined
  type: string | null | undefined
}

const searchForm = reactive<SearchForm>({
  keyword: undefined,
  type: undefined,
})

// 新增/编辑表单
const formRef = ref<FormInst | null>(null)
const form = reactive<Omit<Permission, 'id' | 'children' | 'createdAt' | 'updatedAt'>>({
  name: '',
  code: '',
  level: 0,
  isLeaf: true,
  description: '',
  pid: 0,
  status: 'active',
})

const rules: FormRules = {
  name: {
    required: true,
    message: '请输入权限名称',
  },
  code: {
    required: true,
    message: '请输入权限编码',
  },
  description: {
    required: false,
    message: '请输入权限描述',
  },
  pid: {
    required: false,
    message: '请选择父权限',
  },
}

// 权限数据
const permissions = ref<Permission[]>([])

// 当前编辑的权限ID
let currentPermissionId: number

// 将权限树形结构转换为NTreeSelect需要的格式
const permissionTreeOptions = computed(() => {
  // 首先从扁平数据构建树形结构
  const treeData = buildTree(permissions.value)

  // 递归转换权限树形结构为NTreeSelect需要的格式
  const transformPermission = (permission: Permission): any => {
    // 过滤掉当前编辑的权限，避免循环引用
    if (permission.id === currentPermissionId) {
      return null
    }

    const treeNode: { key: number; label: string; children: any[]; permission: Permission } = {
      key: permission.id,
      label: permission.name,
      children: [],
      // 保留原始权限数据
      permission,
    }

    // 递归处理子权限
    if (permission.children && permission.children.length > 0) {
      const validChildren = permission.children
        .map(child => transformPermission(child))
        .filter((child): child is any => child !== null)

      if (validChildren.length > 0) {
        treeNode.children = validChildren
      }
    }

    return treeNode
  }

  // 处理根权限列表
  return treeData
    .map(permission => transformPermission(permission))
    .filter((permission): permission is any => permission !== null)
})

// 统计数据
const permissionStats = reactive({
  total: 0,
  menuPermissions: 0,
  apiPermissions: 0,
  buttonPermissions: 0,
})
// 统计数据展示
const statCards = reactive([
  {
    title: '总权限数',
    value: computed(() => permissionStats.total),
    type: 'total',
    icon: 'iconify ph--key',
    color: '#3b82f6',
  },
  {
    title: '菜单权限',
    value: computed(() => permissionStats.menuPermissions),
    type: 'menu',
    icon: 'iconify ph--menu',
    color: '#10b981',
  },
  {
    title: '接口权限',
    value: computed(() => permissionStats.apiPermissions),
    type: 'api',
    icon: 'iconify ph--code',
    color: '#6366f1',
  },
  {
    title: '按钮权限',
    value: computed(() => permissionStats.buttonPermissions),
    type: 'button',
    icon: 'iconify ph--folder-open',
    color: '#f59e0b',
  }
])
// 将扁平数据转换为树形结构
function buildTree(flatData: Permission[]): Permission[] {
  const tree: Permission[] = []
  const map = new Map<number, Permission>()

  // 首先创建所有节点的映射，并初始化children数组
  flatData.forEach((item) => {
    map.set(item.id, { ...item, children: [] })
  })

  // 然后构建树形结构
  flatData.forEach((item) => {
    const node = map.get(item.id)
    if (node) {
      if (item.pid === 0 || !item.pid) {
        // 根节点
        tree.push(node)
      } else {
        // 子节点，添加到父节点的children数组中
        const parent = map.get(item.pid)
        if (parent) {
          parent.children!.push(node)
        }
      }
    }
  })

  // 为每个节点设置正确的isLeaf属性
  function setIsLeaf(node: Permission) {
    if (node.children && node.children.length > 0) {
      node.isLeaf = false
      // 递归处理子节点
      node.children.forEach(setIsLeaf)
    } else {
      node.isLeaf = true
    }
  }

  // 处理所有根节点
  tree.forEach(setIsLeaf)

  return tree
}

// 扁平化树形数据
function flattenTree(tree: Permission[]): Permission[] {
  const result: Permission[] = []

  function traverse(node: Permission) {
    // 创建一个新对象，不包含children字段
    const { children, ...rest } = node
    result.push(rest)

    if (children) {
      children.forEach((child) => traverse(child))
    }
  }
  tree.forEach((node) => traverse(node))
  return result
}

// 获取权限列表
async function getDataList() {
  isRequestLoading.value = true
  try {
    const res = await roleApi.getPermissions()

    // 如果返回的是树形结构，先扁平化
    let flatPermissions = Array.isArray(res) ? res : []

    // 确保权限数据是扁平结构
    if (flatPermissions.length > 0) {
      const firstItem = flatPermissions[0]
      // 检查第一个元素是否有children字段，并且children字段有数据
      const hasChildren = firstItem && firstItem.children && firstItem.children.length > 0

      // 如果有children字段且有数据，说明是树形结构，需要扁平化
      if (hasChildren) {
        flatPermissions = flattenTree(flatPermissions)
      }
    }
    permissions.value = flatPermissions // 保存扁平数据用于层级计算

    // 构建树形结构用于展示
    let treeData = buildTree(flatPermissions)

    // 根据关键词搜索
    if (searchForm.keyword) {
      const keyword = searchForm.keyword.toLowerCase()
      treeData = filterTreeByKeyword(treeData, keyword)
    }

    // 根据权限类型过滤
    if (searchForm.type) {
      treeData = filterTreeByType(treeData, searchForm.type)
    }

    // 转换回扁平化数据以便统计
    const flattenedData = flattenTree(treeData)

    // 更新统计数据
    permissionStats.total = flattenedData.length
    // 使用API返回的isLeaf属性来计算叶子节点和非叶子节点数量
    permissionStats.menuPermissions = flattenedData.filter((p) => p.code.startsWith('menu:')).length
    permissionStats.apiPermissions = flattenedData.filter((p) => p.code.startsWith('api:')).length
    permissionStats.buttonPermissions = flattenedData.filter((p) => p.code.startsWith('button:')).length

    // 使用树形数据展示
    dataList.value = treeData
  } catch {
    message.error('获取权限列表失败')
  } finally {
    isRequestLoading.value = false
  }
}

// 根据关键词过滤树形数据
function filterTreeByKeyword(tree: Permission[], keyword: string): Permission[] {
  return tree.reduce((result, node) => {
    // 检查当前节点是否匹配
    const nodeMatches =
      node.name.toLowerCase().includes(keyword) ||
      node.code.toLowerCase().includes(keyword) ||
      (node.description && node.description.toLowerCase().includes(keyword))

    // 递归过滤子节点
    const filteredChildren = node.children ? filterTreeByKeyword(node.children, keyword) : []

    // 如果当前节点匹配或有匹配的子节点，则保留该节点
    if (nodeMatches || filteredChildren.length > 0) {
      result.push({
        ...node,
        children: filteredChildren,
      })
    }

    return result
  }, [] as Permission[])
}

// 根据权限类型过滤树形数据
function filterTreeByType(tree: Permission[], type: string): Permission[] {
  return tree.reduce((result, node) => {
    // 检查当前节点是否匹配
    let nodeMatches = false
    if (type === 'menu') {
      nodeMatches = node.code.startsWith('menu:')
    } else if (type === 'api') {
      nodeMatches = node.code.startsWith('api:')
    } else if (type === 'button') {
      nodeMatches = !node.code.startsWith('menu:') && !node.code.startsWith('api:')
    }

    // 递归过滤子节点
    const filteredChildren = node.children ? filterTreeByType(node.children, type) : []

    // 如果当前节点匹配或有匹配的子节点，则保留该节点
    if (nodeMatches || filteredChildren.length > 0) {
      result.push({
        ...node,
        children: filteredChildren,
      })
    }
    return result
  }, [] as Permission[])
}

// 打开新增权限模态框
function openAddModal() {
  // 重置表单
  form.name = ''
  form.code = ''
  form.description = ''
  form.pid = 0
  form.level = 0
  form.isLeaf = true
  form.status = 'active'

  modal.create({
    autoFocus: false,
    title: '新增权限',
    preset: 'dialog',
    draggable: true,
    positiveText: '保存',
    negativeText: '取消',
    style: {
      width: '500px',
      ...(isMaxMd.value ? { marginInline: '16px' } : {}),
    },
    content: () => {
      return h('div', [
        h(
          NForm,
          {
            ref: (instance) => (formRef.value = instance as FormInst | null),
            model: form,
            rules: rules,
            labelPlacement: 'left',
            labelWidth: 80,
          },
          [
            h(NFormItem, { label: '权限名称', path: 'name' }, [
              h(NInput, {
                value: form.name,
                'onUpdate:value': (value: string) => (form.name = value),
                clearable: true,
                placeholder: '请输入权限名称',
              }),
            ]),
            h(NFormItem, { label: '权限编码', path: 'code' }, [
              h(NInput, {
                value: form.code,
                'onUpdate:value': (value: string) => (form.code = value),
                clearable: true,
                placeholder: '请输入权限编码，如：menu:dashboard',
              }),
            ]),
            h(NFormItem, { label: '父权限', path: 'pid' }, [
              h(NTreeSelect, {
                value: form.pid,
                'onUpdate:value': (value: number | undefined) => {
                  form.pid = value
                  // 自动计算level和isLeaf
                  if (value) {
                    const parentPermission = findPermissionById(value, permissions.value)
                    if (parentPermission) {
                      form.level = parentPermission.level + 1
                    }
                  } else {
                    form.level = 0
                  }
                },
                placeholder: '选择父权限（可选）',
                clearable: true,
                options: permissionTreeOptions.value,
                allowClear: true,
                showPath: true,
                treeProps: {
                  blockNode: true,
                },
              }),
            ]),
            h(NFormItem, { label: '权限描述', path: 'description' }, [
              h(NInput, {
                value: form.description,
                'onUpdate:value': (value: string) => (form.description = value),
                clearable: true,
                placeholder: '请输入权限描述',
                type: 'textarea',
                rows: 3,
              }),
            ]),
          ],
        ),
      ])
    },
    onPositiveClick: async () => {
      if (formRef.value) {
        const valid = await formRef.value.validate()
        if (valid) {
          // 新增权限
          try {
            await roleApi.createPermission(form)
            message.success('权限创建成功')
            getDataList()
            modal.destroyAll()
          } catch {
            message.error('权限创建失败')
          }
        }
      }
    },
    onNegativeClick: () => {
      modal.destroyAll()
    },
  })
}

// 打开编辑权限模态框
function openEditModal(permission: Permission) {
  // 填充表单数据
  form.name = permission.name
  form.code = permission.code
  form.description = permission.description
  form.pid = permission.pid
  form.level = permission.level
  form.isLeaf = permission.isLeaf
  form.status = permission.status

  currentPermissionId = permission.id

  modal.create({
    autoFocus: false,
    title: '编辑权限',
    preset: 'dialog',
    draggable: true,
    positiveText: '保存',
    negativeText: '取消',
    style: {
      width: '500px',
      ...(isMaxMd.value ? { marginInline: '16px' } : {}),
    },
    content: () => {
      return h('div', [
        h(
          NForm,
          {
            ref: (instance) => (formRef.value = instance as FormInst | null),
            model: form,
            rules: rules,
            labelPlacement: 'left',
            labelWidth: 80,
          },
          [
            h(NFormItem, { label: '权限名称', path: 'name' }, [
              h(NInput, {
                value: form.name,
                'onUpdate:value': (value: string) => (form.name = value),
                clearable: true,
                placeholder: '请输入权限名称',
              }),
            ]),
            h(NFormItem, { label: '权限编码', path: 'code' }, [
              h(NInput, {
                value: form.code,
                'onUpdate:value': (value: string) => (form.code = value),
                clearable: true,
                placeholder: '请输入权限编码，如：menu:dashboard',
              }),
            ]),
            h(NFormItem, { label: '父权限', path: 'pid' }, [
              h(NTreeSelect, {
                value: form.pid,
                'onUpdate:value': (value: number | undefined) => {
                  form.pid = value
                  // 自动计算level和isLeaf
                  if (value) {
                    const parentPermission = findPermissionById(value, permissions.value)
                    if (parentPermission) {
                      form.level = parentPermission.level + 1
                    }
                  } else {
                    form.level = 0
                  }
                },
                placeholder: '选择父权限（可选）',
                clearable: true,
                options: permissionTreeOptions.value.filter(opt => opt.key !== permission.id),
                allowClear: true,
                showPath: true,
                treeProps: {
                  blockNode: true,
                },
              }),
            ]),
            h(NFormItem, { label: '权限描述', path: 'description' }, [
              h(NInput, {
                value: form.description,
                'onUpdate:value': (value: string) => (form.description = value),
                clearable: true,
                placeholder: '请输入权限描述',
                type: 'textarea',
                rows: 3,
              }),
            ]),
          ],
        ),
      ])
    },
    onPositiveClick: async () => {
      if (formRef.value) {
        const valid = await formRef.value.validate()
        if (valid && currentPermissionId) {
          // 编辑权限
          try {
            await roleApi.updatePermission(currentPermissionId, form)
            message.success('权限更新成功')
            getDataList()
            modal.destroyAll()
          } catch {
            message.error('权限更新失败')
          }
        }
      }
    },
    onNegativeClick: () => {
      modal.destroyAll()
    },
  })
}

// 删除权限
async function deletePermissionHandler(id: number) {
  try {
    await roleApi.deletePermission(id)
    message.success('权限删除成功')
    getDataList()
  } catch {
    message.error('权限删除失败')
  }
}

// 批量删除权限
async function batchDeleteHandler() {
  if (checkedRowKeys.value.length === 0) {
    message.warning('请选择要删除的权限')
    return
  }

  // 检查是否有非叶子节点被选中，使用API返回的isLeaf属性
  const hasNonLeafNodes = checkedRowKeys.value.some((key) => {
    const permission = findPermissionById(key, permissions.value)
    return permission && !permission.isLeaf
  })

  if (hasNonLeafNodes) {
    message.warning('只能删除叶子节点（没有子节点的权限）')
    return
  }

  try {
    await roleApi.batchDeletePermissions(checkedRowKeys.value)
    message.success('批量删除成功')
    getDataList()
    checkedRowKeys.value = []
  } catch  {
    message.error('批量删除失败')
  }
}

// 根据ID查找权限
function findPermissionById(id: number, permissions: Permission[]): Permission | undefined {
  for (const permission of permissions) {
    if (permission.id === id) {
      return permission
    }
    if (permission.children) {
      const found = findPermissionById(id, permission.children)
      if (found) {
        return found
      }
    }
  }
  return undefined
}

// 表格列配置 - 渲染函数提取
const renderPermissionType = (row: Permission) => {
  const code = row.code
  if (code.startsWith('menu:')) {
    return h(
      NTag,
      {
        type: 'success',
        bordered: false,
        size: 'small',
      },
      '菜单权限',
    )
  } else if (code.startsWith('api:')) {
    return h(
      NTag,
      {
        type: 'info',
        bordered: false,
        size: 'small',
      },
      '接口权限',
    )
  } else {
    return h(
      NTag,
      {
        type: 'warning',
        bordered: false,
        size: 'small',
      },
      '按钮权限',
    )
  }
}

const renderChildrenCount = (row: Permission) => {
  const childrenCount = row.children?.length || 0
  if (childrenCount === 0) return ''

  return h(
    NTag,
    {
      type: 'default',
      bordered: false,
      size: 'small',
    },
    `${childrenCount} 个子权限`,
  )
}

const renderPermissionName = (row: Permission) => {
  return h(
    'div',
    {
      class: 'flex items-center',
      style: {
        display: 'inline-flex',
        verticalAlign: 'middle',
        alignItems: 'center',
        height: '100%',
      },
    },
    [h('span', { class: 'font-medium' }, row.name), renderChildrenCount(row)],
  )
}

const renderActions = (row: Permission) => {
  const actions = []

  // 所有节点都可以编辑
  actions.push(
    h(
      NButton,
      {
        secondary: true,
        type: 'primary',
        size: 'small',
        onClick: () => openEditModal(row),
      },
      {
        icon: () => h('span', { class: 'iconify ph--pencil' }),
        default: () => '编辑',
      },
    ),
  )

  // 只有叶子节点可以删除
  if (row.isLeaf) {
    actions.push(
      h(
        NPopconfirm,
        {
          positiveText: '确定',
          negativeText: '取消',
          onPositiveClick: () => deletePermissionHandler(row.id),
        },
        {
          trigger: () => {
            return h(
              NButton,
              {
                secondary: true,
                type: 'error',
                size: 'small',
              },
              {
                icon: () => h('span', { class: 'iconify ph--trash' }),
                default: () => '删除',
              },
            )
          },
          default: () => '确认删除吗？删除后将影响所有关联角色的权限。',
        },
      ),
    )
  }

  return actions
}

// 表格列配置
const columns = computed<DataTableColumns<Permission>>(() => {
  // 基础列配置 - 小屏幕下显示的核心列
  const baseColumns: DataTableColumns<Permission> = [
    {
      type: 'selection',
      options: ['all', 'none'],
    },
    {
      key: 'name',
      title: '权限名称',
      render: renderPermissionName,
      align: 'left',
      ellipsis: true,
    },
    {
      key: 'type',
      title: '权限类型',
      render: renderPermissionType,
      ellipsis: true,
    },
    {
      key: 'actions',
      title: '',
      width: isActionsExpanded.value ? 200 : 0,
      fixed: 'right',
      render: (row) => {
        return h('div', { class: 'flex gap-2 items-center p-2' }, [
          // 只有当展开时才显示操作按钮
          ...(isActionsExpanded.value ? renderActions(row) : []),
        ])
      },
    },
  ]

  // 中屏幕及以上添加更多列
  if (!isMaxMd.value) {
    baseColumns.splice(3, 0, {
      key: 'code',
      title: '权限编码',
      ellipsis: true,
    })
  }

  // 大屏幕添加完整列
  if (!isMaxLg.value) {
    baseColumns.splice(4, 0, {
      key: 'description',
      title: '权限描述',
      ellipsis: true,
    })
    baseColumns.splice(5, 0, {
      key: 'createdAt',
      title: '创建时间',
      render: (row) => new Date(row.createdAt).toLocaleString(),
      ellipsis: true,
    })
    baseColumns.splice(6, 0, {
      key: 'updatedAt',
      title: '更新时间',
      render: (row) => new Date(row.updatedAt).toLocaleString(),
      ellipsis: true,
    })
  }

  return baseColumns
})
// 重置搜索表单
function resetSearchForm() {
  searchForm.keyword = null
  searchForm.type = null
  getDataList()
}

// 初始化数据
async function initData() {
  await getDataList()
}
initData()
</script>

<template>
  <ScrollContainer
    wrapper-class="flex flex-col gap-y-4"
    :scrollable="isMaxLg"
  >
    <!-- 统计卡片 -->
    <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-5">
      <NCard
        v-for="card in statCards"
        :key="card.type"
        size="small"
        class="transition-all hover:shadow-md"
      >
        <div class="flex items-center justify-between">
          <div>
            <h3 class="text-sm font-medium text-neutral-500 dark:text-neutral-400">
              {{ card.title }}
            </h3>
            <div class="mt-1 flex items-baseline gap-2">
              <NNumberAnimation
              :from="0"
              :to="card.value"
              :duration="1000"
              class="text-2xl font-semibold"
              :class="{
                'text-blue-500': card.type === 'total',
                'text-green-500': card.type === 'menu',
                'text-indigo-500': card.type === 'api',
                'text-amber-500': card.type === 'button',
              }"
            />
              <span class="text-sm text-neutral-500 dark:text-neutral-400">个</span>
            </div>
          </div>
          <div
            :class="`flex size-10 items-center justify-center rounded-full text-white`"
            :style="{ backgroundColor: card.color }"
          >
            <span
              :class="card.icon"
              class="text-xl"
            ></span>
          </div>
        </div>
      </NCard>
    </div>

    <!-- 权限管理表格 -->
    <NCard
      :size="isMaxMd ? 'small' : undefined"
      class="flex-1"
      content-class="flex flex-col"
    >
      <!-- 工具栏 -->
      <div
        class="mb-4 flex flex-nowrap items-center justify-between gap-x-4 gap-y-2 overflow-x-auto"
      >
        <!-- 搜索表单 -->
        <div class="flex flex-wrap items-center gap-2">
          <NInput
            v-model:value="searchForm.keyword"
            clearable
            placeholder="权限名称/编码"
            @keyup.enter="getDataList"
            style="width: 180px"
          />
          <NSelect
            v-model:value="searchForm.type"
            :options="[
              { label: '菜单权限', value: 'menu' },
              { label: '接口权限', value: 'api' },
              { label: '按钮权限', value: 'button' },
            ]"
            placeholder="权限类型"
            clearable
            @update:value="getDataList"
            style="width: 120px"
          />
          <NButton
            type="info"
            @click="getDataList"
            :loading="isRequestLoading"
            class="whitespace-nowrap"
          >
            <template #icon>
              <span class="iconify ph--magnifying-glass"></span>
            </template>
            查询
          </NButton>
          <NButton
            type="warning"
            @click="resetSearchForm"
            class="whitespace-nowrap"
          >
            <template #icon>
              <span class="iconify ph--arrow-clockwise"></span>
            </template>
            重置
          </NButton>
        </div>

        <div class="flex items-center gap-x-4 self-center">
          <NButton
            type="primary"
            @click="openAddModal"
          >
            <template #icon>
              <span class="iconify ph--plus-circle"></span>
            </template>
            新增权限
          </NButton>
          <NButton
            type="error"
            :disabled="checkedRowKeys.length === 0"
            @click="batchDeleteHandler"
          >
            <template #icon>
              <span class="iconify ph--trash"></span>
            </template>
            批量删除 ({{ checkedRowKeys.length }})
          </NButton>
          <NButton
            type="default"
            size="small"
            @click="isActionsExpanded = !isActionsExpanded"
            class="transition-all duration-300"
            :hidden="dataList.length === 0 && !isRequestLoading"
          >
            <template #icon>
              <span
                class="iconify transition-transform duration-300"
                :class="isActionsExpanded ? 'ph--caret-right' : 'ph--caret-left'"
              />
            </template>
          </NButton>
        </div>
      </div>

      <!-- 数据表格 -->
      <div class="flex flex-1 flex-col">
        <NDataTable
          class="flex-1"
          v-model:checked-row-keys="checkedRowKeys"
          :remote="true"
          :flex-height="!isMaxLg"
          :scroll-x="1800"
          :columns="columns"
          :data="dataList"
          :row-key="(row) => row.id"
          :tree-props="{ childrenKey: 'children' }"
          :loading="isRequestLoading"
          :striped="true"
          :bordered="false"
        />

        <!-- 树形数据不需要分页 -->
        <div class="mt-3">
          <span>已选择&nbsp;{{ checkedRowKeys.length }}&nbsp;条</span>
        </div>
      </div>
    </NCard>
  </ScrollContainer>
</template>
